﻿using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Utils.Common.CompressProj;
 

namespace Utils.Common.CompressProj
{
  public  class RarOperate
    {

        private CommonFunctions commFuncs = CommonFunctions.getInstance();

        #region 单例模式

        private static RarOperate uniqueInstance;
        private static object _lock = new object();

        private RarOperate() { }
        public static RarOperate getInstance()
        {
            if (null == uniqueInstance)      //确认要实例化后再进行加锁，降低加锁的性能消耗。
            {
                lock (_lock)
                {
                    if (null == uniqueInstance)
                    {
                        uniqueInstance = new RarOperate();
                    }
                }
            }
            return uniqueInstance;
        }

        #endregion

        #region 压缩

        /// <summary>
        /// 使用Rar.exe压缩对象
        /// </summary>
        /// <param name="rarRunPathName">Rar.exe路径+对象名</param>
        /// <param name="objectPathName">被压缩对象路径+对象名</param>
        /// <param name="objectRarPathName">对象压缩后路径+对象名</param>
        /// <returns></returns>
        public CompressResults CompressObject(string rarRunPathName, string objectPathName, string objectRarPathName, string password)
        {
            try
            {
                //被压缩对象是否存在
                int beforeObjectNameIndex = objectPathName.LastIndexOf('\\');
                string objectPath = objectPathName.Substring(0, beforeObjectNameIndex);
                //System.IO.DirectoryInfo directoryInfo = new System.IO.DirectoryInfo(objectPathName);
                if (Directory.Exists(objectPathName)/*directoryInfo.Exists*/ == false && System.IO.File.Exists(objectPathName) == false)
                {
                    return CompressResults.SourceObjectNotExist;
                }

                //将对应字符串转换为命令字符串
                string rarCommand = "\"" + rarRunPathName + "\"";
                string objectPathNameCommand = "\"" + objectPathName + "\"";
                int beforeObjectRarNameIndex = objectRarPathName.LastIndexOf('\\');
                int objectRarNameIndex = beforeObjectRarNameIndex + 1;
                string objectRarName = objectRarPathName.Substring(objectRarNameIndex);
                string rarNameCommand = "\"" + objectRarName + "\"";
                string objectRarPath = objectRarPathName.Substring(0, beforeObjectRarNameIndex);
                //目标目录、文件是否存在
                if (System.IO.Directory.Exists(objectRarPath) == false)
                {
                    System.IO.Directory.CreateDirectory(objectRarPath);
                }
                else if (System.IO.File.Exists(objectRarPathName) == true)
                {
                    System.IO.File.Delete(objectRarPathName);
                }
                //Rar压缩命令
                string commandInfo = "a " + rarNameCommand + " " + objectPathNameCommand + " -y -p" + password + " -ep1 -r -s- -rr ";
                //另起一线程执行
                commFuncs.ExecuteProcess(rarCommand, commandInfo, objectRarPath, ProcessWindowStyle.Hidden);

                CompressRarTest(rarCommand, objectRarPathName, password);
                CorrectConfusedRar(objectRarPathName);
            }
            catch (Exception ex)
            {
                LogHelper.LogError(ex.Message, ex);
                return CompressResults.UnKnown;
            }
            return CompressResults.Success;
        }

        #endregion

        #region 解压

        /// <summary>
        /// 解压：将文件解压到某个文件夹中。 注意：要对路径加上双引号，避免带空格的路径，在rar命令中失效
        /// </summary>
        /// <param name="rarRunPath">rar.exe的名称及路径</param>
        /// <param name="fromRarPath">被解压的rar文件路径</param>
        /// <param name="toRarPath">解压后的文件存放路径</param>
        /// <returns></returns>
        public UnCompressResults unCompressRAR( String objectRarPathName, String objectPath, string password)
        {
            try
            {
                String rarRunPath = ExistsWinRar();
                bool isFileExist = File.Exists(objectRarPathName);
                if (false == isFileExist)
                {
                    //MessageBox.Show("解压文件不存在！" + objectRarPathName);
                    return UnCompressResults.SourceObjectNotExist;
                }
                File.SetAttributes(objectRarPathName, FileAttributes.Normal);     //去掉只读属性

                if (Directory.Exists(objectPath) == false)
                {
                    Directory.CreateDirectory(objectPath);
                }

                String rarCommand = "\"" + rarRunPath + "\"";
                String objectPathCommand = "\"" + objectPath + "\\\"";
                String commandInfo = "x \"" + objectRarPathName + "\" " + objectPath + " -y -p" + password;

                commFuncs.ExecuteProcess(rarCommand, commandInfo, objectPath, ProcessWindowStyle.Hidden);

                //MessageBox.Show("解压缩成功！" + objectRarPathName);
                return UnCompressResults.Success;
            }
            catch
            {
                //MessageBox.Show("解压缩失败！" + objectRarPathName);
                return UnCompressResults.UnKnown;
            }
        }

        public static string ExistsWinRar()
        {
            string result = string.Empty;

            string key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\WinRAR.exe";
            RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(key);
            if (registryKey != null)
            {
                result = registryKey.GetValue("").ToString();
            }
            registryKey.Close();

            return result;
        }

        #endregion

        #region 进程



        #endregion

        #region 测试压缩文件

        /// <summary>
        /// 测试压缩后的文件是否正常。
        /// </summary>
        /// <param name="rarRunPath"></param>
        /// <param name="rarFilePathName"></param>
        public bool CompressRarTest(String rarRunPath, String rarFilePathName, string password)
        {
            bool isOk = false;
            String commandInfo = "t -p" + password + " \"" + rarFilePathName + "\"";

            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.FileName = rarRunPath;
            startInfo.Arguments = commandInfo;
            startInfo.WindowStyle = ProcessWindowStyle.Hidden;
            startInfo.UseShellExecute = false;
            startInfo.RedirectStandardOutput = true;
            startInfo.CreateNoWindow = true;

            Process process = new Process();
            process.StartInfo = startInfo;
            process.Start();

            StreamReader streamReader = process.StandardOutput;

            process.WaitForExit();

            if (streamReader.ReadToEnd().ToLower().IndexOf("error") >= 0)
            {
                //MessageBox.Show("压缩文件已损坏！");
                isOk = false;
            }
            else
            {
                //MessageBox.Show("压缩文件良好！");
                isOk = true;
            }
            process.Close();
            process.Dispose();
            return isOk;
        }


        /// <summary>
        /// 混淆Rar
        /// </summary>
        /// <param name="objectRarPathName">rar路径+名</param>
        /// <returns></returns>
        public bool ConfusedRar(string objectRarPathName)
        {
            try
            {
                //混淆
                System.IO.FileStream fs = new FileStream(objectRarPathName, FileMode.Open);
                fs.WriteByte(0x53);
                fs.Close();
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.LogError(ex.Message, ex);
                //MessageBox.Show("混淆Rar失败！" + ex.Message);
                return false;
            }
        }

        /// <summary>
        /// 纠正混淆的Rar
        /// </summary>
        /// <param name="objectRarPathName">rar路径+名</param>
        /// <returns></returns>
        public bool CorrectConfusedRar(string objectRarPathName)
        {
            bool isCorrect = false;
            try
            {
                //先判断一下待解压文件是否经过混淆
                FileStream fsRar = new FileStream(objectRarPathName, FileMode.Open, FileAccess.Read);
                int b = fsRar.ReadByte();
                fsRar.Close();
                if (b != 0x52)     //R:0x52 原始开始值
                {
                    string strTempFile = System.IO.Path.GetTempFileName();
                    File.Copy(objectRarPathName, strTempFile, true);
                    File.SetAttributes(strTempFile, FileAttributes.Normal);     //去掉只读属性
                    FileStream fs = new FileStream(strTempFile, FileMode.Open);
                    fs.WriteByte(0x52);
                    fs.Close();
                    System.IO.File.Delete(objectRarPathName);
                    File.Copy(strTempFile, objectRarPathName, true);
                }
                isCorrect = true;
                return isCorrect;
            }
            catch(Exception ex)
            {
                LogHelper.LogError(ex.Message, ex);
                return isCorrect;
            }
        }


        #endregion
 
    }
}
